#include "code.h"
#include "reg.h"
#include <map>
#include <cassert>
#include <algorithm>
using namespace code;
using namespace reg;
using namespace std;

static string OperandToString(Operand& operand)
{
    if (holds_alternative<int>(operand)) 
    { return to_string(get<int>(operand)); }
    else { return std::get<std::string>(operand); }
}

string Instruction::ToString()
{
    string op_str;
    switch (op)
    {
        case OP_ADD: op_str = "add"; break;
        case OP_ADDI: op_str = "addi"; break;
        case OP_SUB: op_str = "sub"; break;
        case OP_MUL: op_str = "mul"; break;
        case OP_DIV: op_str = "div"; break;
        case OP_REM: op_str = "rem"; break;
        case OP_SNE: op_str = "sne"; break;
        case OP_SEQ: op_str = "seq"; break;
        case OP_SGT: op_str = "sgt"; break;
        case OP_SLT: op_str = "slt"; break;
        case OP_SGE: op_str = "sge"; break;
        case OP_SLE: op_str = "sle"; break;
        case OP_AND: op_str = "and"; break;
        case OP_OR: op_str = "or"; break;
        case OP_LW: op_str = "lw"; break;
        case OP_SW: op_str = "sw"; break;
        case OP_LI: op_str = "li"; break;
        case OP_MV: op_str = "mv"; break;
        case OP_BNEZ: op_str = "bnez"; break;
        case OP_J: op_str = "j"; break;
        case OP_RET: op_str = "ret"; break;
        case OP_CALL: op_str = "call"; break;
        case OP_XOR: op_str = "xor"; break;
        case OP_XORI: op_str = "xori"; break;
        case OP_SLTU: op_str = "sltu"; break;
        case OP_SLTIU: op_str = "sltiu"; break;
        case OP_LUI: op_str = "lui"; break;
        case OP_BNE: op_str = "bne"; break;
        case OP_JAL: op_str = "jal"; break;
        case OP_JALR: op_str = "jalr"; break;
        default: assert(false); break;
    }
    string operands_str;
    if (op == OP_LW || op == OP_SW)
    {
        string operand0_str = OperandToString(operands[0]);
        string operand1_str = OperandToString(operands[1]);
        string operand2_str = OperandToString(operands[2]);
        operands_str = 
            operand0_str + ", " + operand1_str + "(" + operand2_str + ")";
    }
    else
    {
        for (size_t i = 0; i < operands.size(); ++i)
        {
            operands_str += OperandToString(operands[i]);
            if (i != operands.size() - 1) { operands_str += ", "; }
        }
    }
    return op_str + " " + operands_str;
}

string Block::ToString()
{
    string instrs_str = "";
    for (Instruction& instr : instrs) 
    { instrs_str += "\t" + instr.ToString() + "\n"; }
    return label + ":\n" + instrs_str;
}

string Function::ToString()
{
    string blocks_str = "";
    for (size_t i = 0; i < blocks.size(); ++i) 
    { 
        blocks_str += blocks[i].ToString(); 
        if (i != blocks.size() - 1) { blocks_str += "\n"; }
    }
    return blocks_str;
}

string Code::ToString()
{
    string directive_str = ".text\n.globl main\n";
    string funcs_str = "";
    for (size_t i = 0; i < funcs.size(); ++i)
    {
        funcs_str += funcs[i].ToString();
        if (i != funcs.size() - 1) { funcs_str += "\n"; }
    }
    return directive_str + "\n" + funcs_str;
}

Code CodeGenerator::Generate(ir::IR& ir)
{
    Code code;
    for (ir::Function& ir_func : ir.funcs)
    {
        Function func = Generate(ir_func);
        for (Block& block : func.blocks) 
        { ReplaceLabel(block, func.name); }
        code.funcs.push_back(move(func));
    }
    ReplacePseudoInstr(code);
    return code;
}

Function CodeGenerator::Generate(ir::Function& ir_func)
{
    Function func;
    func.name = ir_func.name;
    func.stack_size = ir_func.alloc_instrs.size() * 4;
    Block prologue, epilogue;
    prologue.label = "%";
    epilogue.label = "%end";
    func.blocks.push_back(prologue);
    for (ir::Block& ir_block : ir_func.blocks)
    {
        Block block = Generate(ir_block);
        func.blocks.push_back(move(block));
    }
    func.blocks.push_back(epilogue);
    vector<bool> used_regs = ComputeUsedReg(ir_func);
    ReplaceParam(func, ir_func.params);
    ReplaceStackAddr(func, ir_func.alloc_instrs);
    StoreLoadCalleeSaved(func, used_regs);
    ModifySpRaFp(func, used_regs);
    Instruction ret_instr;
    ret_instr.op = OP_RET;
    func.blocks.back().instrs.push_back(move(ret_instr));
    return func;
}

Block CodeGenerator::Generate(ir::Block& ir_block)
{
    Block block;
    block.label = ir_block.label;
    for (ir::Instruction& ir_instr : ir_block.instrs)
    {
        vector<Instruction> instrs = Generate(ir_instr);
        block.instrs.insert(
            block.instrs.end(), instrs.begin(), instrs.end());
    }
    return block;
}

vector<Instruction> CodeGenerator::Generate(ir::Instruction& ir_instr)
{
    vector<Instruction> instrs;
    switch (ir_instr.op)
    {
        case ir::OP_ADD: 
        case ir::OP_SUB: 
        case ir::OP_MUL:
        case ir::OP_DIV:
        case ir::OP_MOD:
        case ir::OP_AND: 
        case ir::OP_OR:
        case ir::OP_NE:
        case ir::OP_EQ:
        case ir::OP_GT:
        case ir::OP_LT: 
        case ir::OP_GE: 
        case ir::OP_LE:
            instrs = GenerateBinaryInstr(ir_instr); break;
        case ir::OP_LOAD: 
            instrs = GenerateLoadInstr(ir_instr); break;
        case ir::OP_STORE:  
            instrs = GenerateStoreInstr(ir_instr); break;
        case ir::OP_MV:
            instrs = GenerateMvInstr(ir_instr); break;
        case ir::OP_BR: 
            instrs = GenerateBrInstr(ir_instr); break;
        case ir::OP_JMP: 
            instrs = GenerateJmpInstr(ir_instr); break;
        case ir::OP_RET: 
            instrs = GenerateRetInstr(ir_instr); break;
        case ir::OP_CALL:
            instrs = GenerateCallInstr(ir_instr); break;
        default: assert(false); break;
    }
    return instrs;
}

void CodeGenerator::ReplaceLabel(Block& block, string& func_name)
{
    if (block.label.size() > 1) 
    { block.label = func_name.substr(1) + "_" + block.label.substr(1); }
    else { block.label = func_name.substr(1); }
    for (Instruction& instr : block.instrs)
    {
        if (instr.op == OP_BNEZ) 
        {
            string label = get<string>(instr.operands[1]);
            instr.operands[1] = func_name.substr(1) + "_" + label.substr(1);
        }
        else if (instr.op == OP_J)
        {
            string label = get<string>(instr.operands[0]);
            instr.operands[0] = func_name.substr(1) + "_" + label.substr(1);
        }
        else if (instr.op == OP_CALL)
        {
            string label = get<string>(instr.operands[0]);
            instr.operands[0] = label.substr(1);
        }
    }
}

/* 工具：判断一个立即数能否用 12-bit 有符号表示 */
static inline bool is_int12(int imm)
{
    return imm >= INT12_MIN && imm <= INT12_MAX;
}

/* 工具：生成一条新指令的小包装 */
static Instruction make(Opcode op, std::initializer_list<Operand> args)
{
    Instruction i;
    i.op = op;
    i.operands = args;
    return i;
}

void CodeGenerator::ReplacePseudoInstr(Code& code)
{
    string zero_reg_name = "x" + to_string(REG_ZERO);
    string ra_reg_name = "x" + to_string(REG_RA);
    for (Function& func : code.funcs)
    {
        for (Block& block : func.blocks)
        {
            std::vector<Instruction> expanded;

            for (Instruction& instr : block.instrs)
            {
                /* 统一取出寄存器名，方便后面使用 */
                std::string rd, rs1, rs2;
                int imm = 0;
                if (instr.operands.size() >= 1u) rd  = std::get<std::string>(instr.operands[0]);
                if (instr.operands.size() >= 2u) 
                {
                    if (std::holds_alternative<int>(instr.operands[1]))
                        imm = std::get<int>(instr.operands[1]);
                    else
                        rs1 = std::get<std::string>(instr.operands[1]);
                }
                if (instr.operands.size() >= 3u)
                {
                    if (std::holds_alternative<int>(instr.operands[2]))
                        imm = std::get<int>(instr.operands[2]);
                    else
                        rs2 = std::get<std::string>(instr.operands[2]);
                }

                switch (instr.op)
                {
                /* ---------- 比较类伪指令 ---------- */
                case OP_SNE:   //  rd = (rs1 != rs2)  →  xor  rd, rs1, rs2; sltu rd, rd, zero
                    expanded.push_back(make(OP_XOR, {rd, rs1, rs2}));
                    expanded.push_back(make(OP_SLTU, {rd, rd, zero_reg_name}));
                    break;

                case OP_SEQ:   //  rd = (rs1 == rs2)  →  xor  rd, rs1, rs2; seqz rd, rd
                    expanded.push_back(make(OP_XOR, {rd, rs1, rs2}));
                    expanded.push_back(make(OP_SLTIU, {rd, rd, 1}));
                    break;

                case OP_SGT:   //  rd = (rs1 >  rs2)  →  slt rd, rs2, rs1
                    expanded.push_back(make(OP_SLT, {rd, rs2, rs1}));
                    break;

                case OP_SGE:   //  rd = (rs1 >= rs2)  →  slt rd, rs1, rs2; xori rd, rd, 1
                    expanded.push_back(make(OP_SLT, {rd, rs1, rs2}));
                    expanded.push_back(make(OP_XORI, {rd, rd, 1}));
                    break;

                case OP_SLE:   //  rd = (rs1 <= rs2)  →  slt rd, rs2, rs1; xori rd, rd, 1
                    expanded.push_back(make(OP_SLT, {rd, rs2, rs1}));
                    expanded.push_back(make(OP_XORI, {rd, rd, 1}));
                    break;

                /* ---------- 伪加载 / 传送 ---------- */
                case OP_LI:    //  rd = imm
                    if (is_int12(imm))
                    {
                        expanded.push_back(make(OP_ADDI, {rd, zero_reg_name, imm}));
                    }
                    else
                    {
                        /* lui + addi 序列 */
                        int upper = (unsigned)(imm + 0x800) >> 12;
                        int lower = imm - (upper << 12);
                        expanded.push_back(make(OP_LUI, {rd, upper}));
                        if (lower != 0)
                            expanded.push_back(make(OP_ADDI, {rd, rd, lower}));
                    }
                    break;

                case OP_MV:    //  rd = rs1  →  addi rd, rs1, 0
                    expanded.push_back(make(OP_ADDI, {rd, rs1, 0}));
                    break;

                /* ---------- 伪转移 ---------- */
                case OP_BNEZ:  //  bnez rs, label  →  bne rs, zero, label
                    expanded.push_back(make(OP_BNE, {rd, zero_reg_name, rs1}));
                    break;

                case OP_J:     //  j label  →  jal zero, label
                    expanded.push_back(make(OP_JAL, {zero_reg_name, rd}));
                    break;

                case OP_RET:   //  ret  →  jalr zero, ra, 0
                    expanded.push_back(make(OP_JALR, {zero_reg_name, ra_reg_name, 0}));
                    break;

                case OP_CALL:  //  call label  →  jal ra, label
                    expanded.push_back(make(OP_JAL, {ra_reg_name, rd}));
                    break;

                /* ---------- 其余已经是真实指令，原样保留 ---------- */
                default:
                    expanded.push_back(instr);
                    break;
                }
            }

            /* 替换原指令序列 */
            block.instrs.swap(expanded);
        }
    }
}

vector<bool> CodeGenerator::ComputeUsedReg(ir::Function& ir_func)
{
    vector<bool> used_regs(32);
    for (ir::Block& ir_block : ir_func.blocks)
    {
        for (ir::Instruction& ir_instr : ir_block.instrs)
        {
            if (ir_instr.dest != "" && ir_instr.dest[0] == 'x')
            {
                int reg_index = stoi(ir_instr.dest.substr(1));
                used_regs[reg_index] = true;
            }
            if (ir_instr.op == ir::OP_CALL)
            { used_regs[REG_RA] = true; }
        }
    }
    if (ir_func.params.size() > REG_ARG.size())
    { used_regs[REG_FP] = true; }
    return used_regs;
}

void CodeGenerator::ReplaceParam(Function& func, vector<string>& params)
{
    vector<Instruction> new_instrs;
    size_t param_index = 0;
    for (Instruction& instr : func.blocks[1].instrs)
    {
        if (param_index < params.size()
            && holds_alternative<string>(instr.operands[0])
            && get<string>(instr.operands[0]) == params[param_index])
        {
            if (param_index < REG_ARG.size())
            { instr.operands[0] = "x" + to_string(REG_ARG[param_index]); }
            else
            {
                Instruction lw_instr;
                lw_instr.op = OP_LW;
                string a0_reg_name = "x" + to_string(REG_ARG.front());
                lw_instr.operands.push_back(a0_reg_name);
                int offset = (param_index - REG_ARG.size()) * 4;
                lw_instr.operands.push_back(offset);
                string fp_reg_name = "x" + to_string(REG_FP);
                lw_instr.operands.push_back(fp_reg_name);
                new_instrs.push_back(move(lw_instr));
                instr.operands[0] = a0_reg_name;
            }
            ++param_index;
        }
        new_instrs.push_back(instr);
    }
    func.blocks[1].instrs = move(new_instrs);
}

void CodeGenerator::ReplaceStackAddr(
    Function& func, vector<ir::Instruction>& ir_alloc_instrs)
{
    map<string, int> var_offset_map;
    for (size_t i = 0; i < ir_alloc_instrs.size(); ++i)
    {
        string var_name = ir_alloc_instrs[i].dest;
        var_offset_map[var_name] = (ir_alloc_instrs.size() - i - 1) * 4;
    }
    for (Block& block : func.blocks)
    {
        for (Instruction& instr : block.instrs)
        {
            if (instr.op == OP_LW || instr.op == OP_SW)
            {
                string var_name = get<string>(instr.operands[2]);
                if (var_offset_map.count(var_name))
                {
                    instr.operands[1] = var_offset_map[var_name];
                    instr.operands[2] = "x" + to_string(REG_SP);
                }
            }
        }
    }
}

void CodeGenerator::StoreLoadCalleeSaved(Function& func, vector<bool>& used_regs)
{
    vector<Instruction> prologue_instrs;
    vector<Instruction> epilogue_instrs;
    for (int reg_index :REG_CALLEE_SAVED)
    {
        if (used_regs[reg_index]) { func.stack_size += 4; }
    }
    int offset = func.stack_size - 4;
    for (int reg_index : REG_CALLEE_SAVED)
    {
        if (used_regs[reg_index])
        {
            vector<Instruction> sw_lw_instrs = 
                InsertStoreLoadRegInstr(reg_index, offset);
            prologue_instrs.push_back(sw_lw_instrs[0]);
            epilogue_instrs.push_back(sw_lw_instrs[1]);
            offset -= 4;
        }
    }
    func.blocks.front().instrs = move(prologue_instrs);
    func.blocks.back().instrs = move(epilogue_instrs);
}

void CodeGenerator::ModifySpRaFp(Function& func, vector<bool>& used_regs)
{
    vector<Instruction> prologue_instrs;
    vector<Instruction> epilogue_instrs;
    if (used_regs[REG_RA]) { func.stack_size += 4; }
    if (used_regs[REG_FP]) { func.stack_size += 4; }
    Instruction sub_sp_instr;
    sub_sp_instr.op = OP_ADDI;
    string sp_reg_name = "x" + to_string(REG_SP);
    sub_sp_instr.operands.push_back(sp_reg_name);
    sub_sp_instr.operands.push_back(sp_reg_name);
    sub_sp_instr.operands.push_back(-func.stack_size);
    prologue_instrs.push_back(move(sub_sp_instr));
    if (used_regs[REG_RA])
    {
        vector<Instruction> sw_lw_instrs = 
            InsertStoreLoadRegInstr(REG_RA, func.stack_size - 4);
        prologue_instrs.push_back(sw_lw_instrs[0]);
        epilogue_instrs.push_back(sw_lw_instrs[1]);
    }
    if (used_regs[REG_FP])
    {
        vector<Instruction> sw_lw_instrs = 
            InsertStoreLoadRegInstr(REG_FP, func.stack_size - 8);
        prologue_instrs.push_back(sw_lw_instrs[0]);
        epilogue_instrs.push_back(sw_lw_instrs[1]);
        Instruction addi_instr;
        addi_instr.op = OP_ADDI;
        string fp_reg_name = "x" + to_string(REG_FP);
        addi_instr.operands.push_back(fp_reg_name);
        addi_instr.operands.push_back(sp_reg_name);
        addi_instr.operands.push_back(func.stack_size);
        prologue_instrs.push_back(move(addi_instr));
    }
    Instruction add_sp_instr;
    add_sp_instr.op = OP_ADDI;
    add_sp_instr.operands.push_back(sp_reg_name);
    add_sp_instr.operands.push_back(sp_reg_name);
    add_sp_instr.operands.push_back(func.stack_size);
    epilogue_instrs.push_back(move(add_sp_instr));
    func.blocks.front().instrs.insert(
        func.blocks.front().instrs.begin(), 
        prologue_instrs.begin(), prologue_instrs.end());
    func.blocks.back().instrs.insert(
        func.blocks.back().instrs.end(), 
        epilogue_instrs.begin(), epilogue_instrs.end());
}

vector<Instruction> CodeGenerator::GenerateBinaryInstr(ir::Instruction& ir_instr)
{
    vector<Instruction> instrs;
    ir::Instruction ir_instr_copy = ir_instr;
    vector<Instruction> li_instrs = InsertLiInstr(ir_instr_copy);
    instrs.insert(instrs.end(), li_instrs.begin(), li_instrs.end());
    Instruction binary_instr;
    switch (ir_instr_copy.op)
    {
        case ir::OP_ADD: binary_instr.op = OP_ADD; break;
        case ir::OP_SUB: binary_instr.op = OP_SUB; break;
        case ir::OP_MUL: binary_instr.op = OP_MUL; break;
        case ir::OP_DIV: binary_instr.op = OP_DIV; break;
        case ir::OP_MOD: binary_instr.op = OP_REM; break;
        case ir::OP_AND: binary_instr.op = OP_AND; break;
        case ir::OP_OR: binary_instr.op = OP_OR; break;
        case ir::OP_NE: binary_instr.op = OP_SNE; break;
        case ir::OP_EQ: binary_instr.op = OP_SEQ; break;
        case ir::OP_GT: binary_instr.op = OP_SGT; break;
        case ir::OP_LT: binary_instr.op = OP_SLT; break;
        case ir::OP_GE: binary_instr.op = OP_SGE; break;
        case ir::OP_LE: binary_instr.op = OP_SLE; break;
        default: assert(false); break;
    }
    binary_instr.operands.push_back(ir_instr_copy.dest);
    binary_instr.operands.push_back(ir_instr_copy.srcs[0]);
    binary_instr.operands.push_back(ir_instr_copy.srcs[1]);
    instrs.push_back(move(binary_instr));
    return instrs;
}

vector<Instruction> CodeGenerator::GenerateLoadInstr(ir::Instruction& ir_instr)
{
    vector<Instruction> instrs;
    Instruction lw_instr;
    lw_instr.op = OP_LW;
    lw_instr.operands.push_back(ir_instr.dest);
    lw_instr.operands.push_back(0);
    lw_instr.operands.push_back(ir_instr.srcs[0]);
    instrs.push_back(move(lw_instr));
    return instrs;
}

vector<Instruction> CodeGenerator::GenerateStoreInstr(ir::Instruction& ir_instr)
{
    vector<Instruction> instrs;
    ir::Instruction ir_instr_copy = ir_instr;
    vector<Instruction> li_instrs = InsertLiInstr(ir_instr_copy);
    instrs.insert(instrs.end(), li_instrs.begin(), li_instrs.end());
    Instruction sw_instr;
    sw_instr.op = OP_SW;
    sw_instr.operands.push_back(ir_instr_copy.srcs[0]);
    sw_instr.operands.push_back(0);
    sw_instr.operands.push_back(ir_instr_copy.srcs[1]);
    instrs.push_back(move(sw_instr));
    return instrs;
}

vector<Instruction> CodeGenerator::GenerateMvInstr(ir::Instruction& ir_instr)
{
    vector<Instruction> instrs;
    Instruction instr;
    instr.op = holds_alternative<int>(ir_instr.srcs[0])? OP_LI : OP_MV;
    instr.operands.push_back(ir_instr.dest);
    instr.operands.push_back(ir_instr.srcs[0]);
    instrs.push_back(move(instr));
    return instrs;
}

vector<Instruction> CodeGenerator::GenerateBrInstr(ir::Instruction& ir_instr)
{
    vector<Instruction> instrs;
    ir::Instruction ir_instr_copy = ir_instr;
    vector<Instruction> li_instrs = InsertLiInstr(ir_instr_copy);
    instrs.insert(instrs.end(), li_instrs.begin(), li_instrs.end());
    Instruction bneqz_instr;
    bneqz_instr.op = OP_BNEZ;
    bneqz_instr.operands.push_back(ir_instr_copy.srcs[0]);
    bneqz_instr.operands.push_back(ir_instr_copy.srcs[1]);
    instrs.push_back(move(bneqz_instr));
    Instruction j_instr;
    j_instr.op = OP_J;
    j_instr.operands.push_back(ir_instr_copy.srcs[2]);
    instrs.push_back(move(j_instr));
    return instrs;
}

vector<Instruction> CodeGenerator::GenerateJmpInstr(ir::Instruction& ir_instr)
{
    vector<Instruction> instrs;
    Instruction j_instr;
    j_instr.op = OP_J;
    j_instr.operands.push_back(ir_instr.srcs[0]);
    instrs.push_back(move(j_instr));
    return instrs;
}

vector<Instruction> CodeGenerator::GenerateRetInstr(ir::Instruction& ir_instr)
{
    vector<Instruction> instrs;
    ir::Instruction ir_instr_copy = ir_instr;
    if (ir_instr_copy.srcs.size() == 1)
    {
        if (holds_alternative<int>(ir_instr_copy.srcs[0]))
        {
            vector<Instruction> li_instrs = InsertLiInstr(ir_instr_copy);
            instrs.insert(instrs.end(), li_instrs.begin(), li_instrs.end());
        }
        else
        {
            Instruction mv_instr;
            mv_instr.op = OP_MV;
            string reg_name = "x" + to_string(REG_ARG.front());
            mv_instr.operands.push_back(reg_name);
            mv_instr.operands.push_back(ir_instr_copy.srcs[0]);
            instrs.push_back(move(mv_instr));
        }
    }
    Instruction j_instr;
    j_instr.op = OP_J;
    j_instr.operands.push_back("%end");
    instrs.push_back(move(j_instr));
    return instrs;

}

vector<Instruction> CodeGenerator::GenerateCallInstr(ir::Instruction& ir_instr)
{
    vector<Instruction> instrs;
    Instruction call_instr;
    call_instr.op = OP_CALL;
    call_instr.operands.push_back(ir_instr.srcs[0]);
    instrs.push_back(move(call_instr));
    Instruction mv_instr;
    mv_instr.op = OP_MV;
    mv_instr.operands.push_back(ir_instr.dest);
    string reg_name = "x" + to_string(REG_ARG.front());
    mv_instr.operands.push_back(reg_name);
    instrs.push_back(move(mv_instr));
    return instrs;
}

vector<Instruction> CodeGenerator::InsertLiInstr(ir::Instruction& ir_instr)
{
    vector<Instruction> instrs;
    auto reg_index = REG_ARG.begin();
    for (size_t i = 0; i < ir_instr.srcs.size(); ++i)
    {
        if (holds_alternative<int>(ir_instr.srcs[i]))
        {
            Instruction li_instr;
            li_instr.op = OP_LI;
            string reg_name = "x" + to_string(*(reg_index++));
            li_instr.operands.push_back(reg_name);
            li_instr.operands.push_back(ir_instr.srcs[i]);
            instrs.push_back(move(li_instr));
            ir_instr.srcs[i] = reg_name;
        }
    }
    return instrs;
}

vector<Instruction> CodeGenerator::InsertStoreLoadRegInstr(int reg_index, int offset)
{
    vector<Instruction> instrs;
    Instruction sw_instr;
    sw_instr.op = OP_SW;
    string callee_saved_reg_name = "x" + to_string(reg_index);
    sw_instr.operands.push_back(callee_saved_reg_name);
    sw_instr.operands.push_back(offset);
    string sp_reg_name = "x" + to_string(REG_SP);
    sw_instr.operands.push_back(sp_reg_name);
    instrs.push_back(move(sw_instr));
    Instruction lw_instr;
    lw_instr.op = OP_LW;
    lw_instr.operands.push_back(callee_saved_reg_name);
    lw_instr.operands.push_back(offset);
    lw_instr.operands.push_back(sp_reg_name);
    instrs.push_back(move(lw_instr));
    return instrs;
}